package ch.janotta.slawo.da.tables;

import java.util.ArrayList;
import java.util.Arrays;

import ch.janotta.slawo.da.Ability;
import ch.janotta.slawo.da.Entity;
import ch.janotta.slawo.da.Talent;
import ch.janotta.slawo.da.modifier.Modifier;
import ch.janotta.slawo.da.modifier.ModifierFactory;
import ch.janotta.slawo.utilities.Dice;

public class WarriorModifiersTable extends CharacterClassModifiersTable {
  private static final Ability[] PRIMARY_ABILITIES = new Ability[] {
      Ability.Constitution,
      Ability.Dexterity,
      Ability.Strength,
  };

  private static final Ability[] SECONDARY_ABILITIES = new Ability[] {
      Ability.Communication,
      Ability.Cunning,
      Ability.Magic,
      Ability.Perception,
      Ability.Willpower
  };

  private Modifier[][] levelModifiers = new Modifier[][] {
      // Level 1
      new Modifier[] {
          ModifierFactory.getInstance(Talent.ArmorTraining),
      },
      // Level 2
      new Modifier[] {
          
      },
  };

  private final int baseHealth = 30;
  private final Talent[] possibleStartingWeaponGroups = new Talent[] {
      Talent.Axes,
      Talent.Bludgeons,
      Talent.Bows,
      Talent.HeavyBlades,
      Talent.LightBlades,
      Talent.Spears,
      Talent.Staves,
  };
  private final Talent[] possibleStartingTalents = new Talent[] {
      Talent.Chirurgy,
      Talent.Linguistics,
      Talent.Lore,
  };
  private final Talent[] possibleLevel1Talents = new Talent[] {
      Talent.ArcheryStyle,
      Talent.DualWeaponStyle,
      Talent.SingleWeaponStyle,
      Talent.ThrowingWeaponStyle,
      Talent.TwoHanderStyle,
      Talent.WeaponandShieldStyle,
  };

  @Override
  public Ability[] getPrimaryAbilities() {
    return PRIMARY_ABILITIES;
  }

  @Override
  public Ability[] getSecondaryAbilities() {
    return SECONDARY_ABILITIES;
  }

  @Override
  public int getStartingHealth(Entity entity) {
    return baseHealth + entity.getConstitution() + Dice.getD6();
  }

  @Override
  public int getLevelUpHealth(Entity entity) {
    return entity.getConstitution() + Dice.getD6();
  }

  @Override
  public int getStartingMana(Entity entity) {
    return 0;
  }

  @Override
  public int getLevelUpMana(Entity entity) {
    return 0;
  }

  @Override
  public Talent[] getStartingWeaponGroups() {
    Talent[] startingWeaponGroups = new Talent[4];
    startingWeaponGroups[0] = Talent.Brawling;
    int[] randomTableIndexes = getDifferentIndexes(possibleStartingWeaponGroups.length, 3);
    for (int i = 0; i < randomTableIndexes.length; i++) {
      startingWeaponGroups[i + 1] = possibleStartingWeaponGroups[randomTableIndexes[i] - 1];
    }
    return startingWeaponGroups;
  }

  @Override
  public Talent getStartingTalent() {
    int lastPossibleTalent = possibleStartingTalents.length;
    int randomTalentNumber = Dice.getRandomNumber(lastPossibleTalent);
    int tableIndex = randomTalentNumber - 1; // random number starts with 1, array indexes start with 0
    return possibleStartingTalents[tableIndex];
  }

  @Override
  public Modifier[] getLevelUpModifiers(int newLevel) {
    if (newLevel == 1) {
      return getLevelOneModifiers();
    } else {
      return levelModifiers[newLevel - 1];
    }
  }

  private Modifier[] getLevelOneModifiers() {
    ArrayList<Modifier> modifiers = new ArrayList<>(Arrays.asList(levelModifiers[0]));
    int[] randomTableIndexes = getDifferentIndexes(possibleLevel1Talents.length, 2);
    for (int i = 0; i < randomTableIndexes.length; i++) {
      modifiers.add(ModifierFactory.getInstance(possibleLevel1Talents[randomTableIndexes[i] - 1]));
    }
    return modifiers.toArray(new Modifier[0]);
  }

  private int[] getDifferentIndexes(int arraySize, int numberOfIndexes) {
    int maxNumberOfIndexes = arraySize < numberOfIndexes ? arraySize : numberOfIndexes;
    int[] indexes = new int[maxNumberOfIndexes];
    for (int i = 0; i < maxNumberOfIndexes; i++) {
      int newIndex = Dice.getRandomNumber(arraySize);
      while (isIndexAlreadyTaken(indexes, newIndex)) {
        newIndex = Dice.getRandomNumber(arraySize);
      }
      indexes[i] = newIndex;
    }
    return indexes;
  }

  private boolean isIndexAlreadyTaken(int[] takenIndexes, int newIndex) {
    for (int i : takenIndexes) {
      if (i == newIndex) return true;
    }
    return false;
  }
}
